%-*-coding: utf-8 -*- 
%abs-guidec.tex
%abs-guidec-chapter04.tex
%Chapter 4. Introduction to Variables and Parameters

\chapter{变量和参数}
变量（variables）是程序和脚本语言表现数据的方式。变量其实只是一个标签（label），也就是一个用于标识计算机内存中存放数据的一系列地址集合的名称而已。

变量在可以出现在数学运算、整数操作或者字符串处理中。

\rule

\section{变量替换}
变量的名称（name）是变量值的占位符。引用变量值的过程成为变量替换（variable substitution）。
\begin{description}
\item[\$] \hfill \\
我们需要仔细区分变量的名字和变量值。如果 variable1 是一个变量的名字，那么 \$variable1 就是对变量值（变量所包含的数据）的引用。
\begin{lstlisting}[nolol=true]
bash$ variable1=23
bash$ echo variable1
variable1
bash$ echo $variable1
23
\end{lstlisting}
在极少数情况下，变量才有可能``赤裸裸''的出现，也就是没有 \$ 的前缀。当变量声明或者被赋值的时候，或者变量被取消时（unset），或者变量被导出时（export），或者在变量是表示一个信号（signal）的特殊情况下。变量赋值可能通过 = （比如 var1=27）实现，或者在 read 语句中，也可能在循环语句的开头处（for var2 in 1 2 3）。

使用双引号（''\ldots''）引用变量并不会影响变量的值替换。这种行为称为部分引用（partial quoting），有时也被称为``弱引用''（weak quoting）。使用单引号（'\ldots'）引用变量会导致变量的值按字面进行处理，并且也不会发生变量替换。这种行为称为全引用（full quoting），有时也被称为强引用（strong quoting）。更详细的细节请参考第五章。

需要注意 \$variable 实际上是 \$\{variable\} 的简化形式。在 \$variable 形式的声明可能引起错误的时候，那么长形式的声明或许可以正常工作（参考10.2节）。
\begin{lstlisting}[caption={变量赋值和替换}, label={Variable assignment and substitution}]
#!/bin/bash
# ex9.sh
# Variables: assignment and substitution
a=375
hello=$a
#-------------------------------------------------------------------------
# No space permitted on either side of = sign when initializing variables.
# What happens if there is a space?
#  "VARIABLE =value"
#           ^
#% Script tries to run "VARIABLE" command with one argument, "=value".
#  "VARIABLE= value"
#            ^
#% Script tries to run "value" command with
#+ the environmental variable "VARIABLE" set to "".
#-------------------------------------------------------------------------
echo hello    # hello
# Not a variable reference, just the string "hello" . . .
echo $hello   # 375
#    ^          This *is* a variable reference.
echo ${hello} # 375
# Also a variable reference, as above.
# Quoting . . .
echo "$hello"    # 375
echo "${hello}"  # 375
echo
hello="A B  C   D"
echo $hello   # A B C D
echo "$hello" # A B  C   D
# As you see, echo $hello   and   echo "$hello"   give different results.
# Why?
# =======================================
# Quoting a variable preserves whitespace.
# =======================================
echo
echo '$hello'  # $hello
#    ^      ^
#  Variable referencing disabled (escaped) by single quotes,
#+ which causes the "$" to be interpreted literally.
# Notice the effect of different types of quoting.
hello=    # Setting it to a null value.
echo "\$hello (null value) = $hello"
#  Note that setting a variable to a null value is not the same as
#+ unsetting it, although the end result is the same (see below).
# --------------------------------------------------------------
#  It is permissible to set multiple variables on the same line,
#+ if separated by white space.
#  Caution, this may reduce legibility, and may not be portable.
var1=21  var2=22  var3=$V3
echo
echo "var1=$var1   var2=$var2   var3=$var3"
# May cause problems with older versions of "sh" . . .
# --------------------------------------------------------------
echo; echo
numbers="one two three"
#           ^   ^
other_numbers="1 2 3"
#               ^ ^
#  If there is whitespace embedded within a variable,
#+ then quotes are necessary.
#  other_numbers=1 2 3                  # Gives an error message.
echo "numbers = $numbers"
echo "other_numbers = $other_numbers"   # other_numbers = 1 2 3
#  Escaping the whitespace also works.
mixed_bag=2\ ---\ Whatever
#           ^    ^ Space after escape (\).
echo "$mixed_bag"         # 2 --- Whatever
echo; echo
echo "uninitialized_variable = $uninitialized_variable"
# Uninitialized variable has null value (no value at all!).
uninitialized_variable=   #  Declaring, but not initializing it --
                          #+ same as setting it to a null value, as above.
echo "uninitialized_variable = $uninitialized_variable"
                          # It still has a null value.
uninitialized_variable=23       # Set it.
unset uninitialized_variable    # Unset it.
echo "uninitialized_variable = $uninitialized_variable"
                                # It still has a null value.
echo
exit 0
\end{lstlisting}
一个未初始化的变量拥有一个空值（``null'' value），这个值不是0，因为根本没有给它分配值。
\begin{lstlisting}[nolol=true]
if [ -z "$unassigned" ]
then
  echo "\$unassigned is NULL."
fi     # $unassigned is NULL.
\end{lstlisting}
在没有给变量赋值之前就使用它可能会引起问题。尽管如此，对一个没有初始化的变量执行数学运算却也是可能存在的。
\begin{lstlisting}[nolol=true]
echo "$uninitialized"                                # (blank line)
let "uninitialized += 5"                             # Add 5 to it.
echo "$uninitialized"                                # 5
#  Conclusion:
#  An uninitialized variable has no value,
#+ however it acts as if it were 0 in an arithmetic operation.
#  This is undocumented (and probably non-portable) behavior,
#+ and should not be used in a script.
\end{lstlisting}
可以参考Example 15.23。
\end{description}
\section{变量赋值}
\begin{description}
\item[=] \hfill \\
赋值运算符（前后都不能存在空格）。
不要把这个跟运行测试的 = 和 -eq 混淆了，那两个不是赋值。在不同的环境下，= 既可以作为赋值运算符，也可以作为测试运算符。
\begin{lstlisting}[caption={简单的变量赋值}, label={Plain Variable Assignment}]
#!/bin/bash
# Naked variables
echo
# When is a variable "naked", i.e., lacking the '$' in front?
# When it is being assigned, rather than referenced.
# Assignment
a=879
echo "The value of \"a\" is $a."
# Assignment using 'let'
let a=16+5
echo "The value of \"a\" is now $a."
echo
# In a 'for' loop (really, a type of disguised assignment):
echo -n "Values of \"a\" in the loop are: "
for a in 7 8 9 11
do
  echo -n "$a "
done
echo
echo
# In a 'read' statement (also a type of assignment):
echo -n "Enter \"a\" "
read a
echo "The value of \"a\" is now $a."
echo
exit 0
\end{lstlisting}
\begin{lstlisting}[caption={简单而新奇的变量赋值}, label={Variable Assignment, plain and fancy}]
#!/bin/bash
a=23              # Simple case
echo $a
b=$a
echo $b
# Now, getting a little bit fancier (command substitution).
a=`echo Hello!`   # Assigns result of 'echo' command to 'a' ...
echo $a
#  Note that including an exclamation mark (!) within a
#+ command substitution construct will not work from the command-line,
#+ since this triggers the Bash "history mechanism."
#  Inside a script, however, the history functions are disabled.
a=`ls -l`         # Assigns result of 'ls -l' command to 'a'
echo $a           # Unquoted, however, it removes tabs and newlines.
echo
echo "$a"         # The quoted variable preserves whitespace.
                  # (See the chapter on "Quoting.")
exit 0
\end{lstlisting}
变量赋值使用\$(\ldots)机制（这是比反引号更新的处理方法）。同时，这也是命令替换的一种形式。
\begin{lstlisting}[nolol=true]
# From /etc/rc.d/rc.local
R=$(cat /etc/redhat-release)
arch=$(uname -m)
\end{lstlisting}
\end{description}

\section{无类型的 Bash 变量！}
\section{特殊的变量类型}
